home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume2 / editors / stevie.4 < prev   
Text File  |  1988-12-02  |  56KB  |  2,907 lines

  1. Path: xanth!mcnc!rutgers!mit-eddie!ll-xn!adelie!infinet!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v02i084:  stevie - vi editor clone, Part04/04
  5. Message-ID: <10422@swan.ulowell.edu>
  6. Date: 2 Dec 88 01:45:43 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 2896
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: grwalter@watcgl.waterloo.edu
  12. Posting-number: Volume 2, Issue 84
  13. Archive-name: editors/stevie.4
  14.  
  15. #    This is a shell archive.
  16. #    Remove everything above and including the cut line.
  17. #    Then run the rest of the file through sh.
  18. #----cut here-----cut here-----cut here-----cut here----#
  19. #!/bin/sh
  20. # shar:    Shell Archiver
  21. #    Run the following text with /bin/sh to create:
  22. #    bsd.c
  23. #    bsd.h
  24. #    makefile.amiga.lattice
  25. #    makefile.bsd
  26. #    makefile.os2
  27. #    makefile.tos
  28. #    makefile.usg
  29. #    os2.c
  30. #    os2.h
  31. #    porting.doc
  32. #    tos.c
  33. #    tos.h
  34. #    unix.c
  35. #    unix.h
  36. #    normal.c
  37. #    sendpacket.c
  38. # This archive created: Thu Dec  1 20:32:15 1988
  39. cat << \SHAR_EOF > bsd.c
  40. /*
  41.  * System-dependent routines for BSD 4.3 UNIX 
  42.  */
  43.  
  44. #include "stevie.h"
  45. #include <sgtty.h>
  46.  
  47. /*
  48.  * inchar() - get a character from the keyboard 
  49.  */
  50. char
  51. inchar()
  52. {
  53.     char            c;
  54.  
  55.     fflush(stdout);        /* flush any pending output */
  56.  
  57.     c = (char) getchar();
  58.  
  59.     return c;
  60. }
  61.  
  62. void
  63. outstr(s)
  64.     char           *s;
  65. {
  66.     while (*s)
  67.     outchar(*s++);
  68. }
  69.  
  70. void
  71. beep()
  72. {
  73.     if (RedrawingDisabled)
  74.     return;
  75.  
  76.     outchar('\007');
  77. }
  78.  
  79. void
  80. delay()
  81. {
  82.     sleep(1);
  83. }
  84.  
  85. static struct sgttyb ostate;
  86.  
  87. void
  88. windinit()
  89. {
  90.     char           *getenv();
  91.     char           *term;
  92.     struct sgttyb   nstate;
  93.  
  94.     term = getenv("TERM");
  95.     if (!term) {
  96.     fprintf(stderr, "Invalid terminal type '%s'\n", term);
  97.     exit(1);
  98.     }
  99.     if ((strncmp(term, "vt", 2) != 0) && (strncmp(term, "xterm", 5) != 0)) {
  100.     fprintf(stderr, "Invalid terminal type '%s'\n", term);
  101.     exit(1);
  102.     }
  103.     Columns = 80;
  104.     P(P_LI) = Rows = 24;
  105.  
  106.     /*
  107.      * Go into cbreak mode 
  108.      */
  109.     ioctl(1, (long) TIOCGETP, (char *) &ostate);
  110.     nstate = ostate;
  111.     nstate.sg_flags = nstate.sg_flags & ~(ECHO | CRMOD) | CBREAK;
  112.     ioctl(1, (long) TIOCSETP, (char *) &nstate);
  113. }
  114.  
  115. void
  116. windexit(r)
  117.     int             r;
  118. {
  119.     fflush(stdout);
  120.  
  121.     ioctl(0, (long) TIOCSETP, (char *) &ostate);
  122.  
  123.     exit(r);
  124. }
  125.  
  126. void
  127. windgoto(r, c)
  128.     int             c;
  129.     int             r;
  130. {
  131.     r++;
  132.     c++;
  133.  
  134.     outstr("\033[");
  135.     if (r >= 10)
  136.     outchar((char) (r / 10 + '0'));
  137.     outchar((char) (r % 10 + '0'));
  138.     outchar(';');
  139.     if (c >= 10)
  140.     outchar((char) (c / 10 + '0'));
  141.     outchar((char) (c % 10 + '0'));
  142.     outchar('H');
  143. }
  144.  
  145. FILE           *
  146. fopenb(fname, mode)
  147.     char           *fname;
  148.     char           *mode;
  149. {
  150.     return fopen(fname, mode);
  151. }
  152. SHAR_EOF
  153. cat << \SHAR_EOF > bsd.h
  154. /*
  155.  * BSD 4.3 Machine-dependent routines. 
  156.  */
  157. char inchar();
  158. #define outchar(c) putchar(c)
  159. void outstr(), beep();
  160. #define remove(path) unlink(path)
  161. int rename();
  162. void windinit(), windexit(), windgoto();
  163. void delay();
  164. SHAR_EOF
  165. cat << \SHAR_EOF > makefile.amiga.lattice
  166. #
  167. # Makefile for Lattice C on Amiga
  168. #
  169.  
  170. .c.o:
  171.     lc $(CFLAGS) $<
  172.  
  173. LIBS = /regexp/regexp.lib
  174. LDFLAGS=
  175.  
  176. CFLAGS = -cu -dAUTO_INDENT
  177. LINKFLAGS = NODEBUG
  178.  
  179. MACH=    amiga.o raw.o sendpacket.o
  180.  
  181. OBJ=    main.o edit.o linefunc.o normal.o cmdline.o charset.o \
  182.     updateRealscreen.o misccmds.o help.o dec.o inc.o search.o alloc.o \
  183.     updateNextscreen.o mark.o screen.o fileio.o param.o $(MACH)
  184.  
  185. all : stevie
  186.  
  187. stevie : $(OBJ)
  188.     BLINK TO stevie FROM lib:c.o $(OBJ) \
  189.         LIBRARY $(LIBS) lib:lc.lib lib:amiga.lib \
  190.         $(LINKFLAGS)
  191.  
  192. clean :
  193.     delete $(OBJ)
  194. SHAR_EOF
  195. cat << \SHAR_EOF > makefile.bsd
  196. #
  197. # Makefile for BSD 4.3 UNIX
  198. #
  199.  
  200. LIBS = ../regexp/regexp.o ../regexp/regsub.o
  201. LDFLAGS=
  202.  
  203. CFLAGS = -I../regexp -pg -g -DDEBUG -DAUTO_INDENT
  204. LINTFLAGS = -I../regexp -DDEBUG -DAUTO_INDENT
  205.  
  206. MACHOBJ=    bsd.o
  207. MACHSRC=    bsd.c
  208.  
  209. SRC=    main.c edit.c linefunc.c normal.c cmdline.c charset.c \
  210.     updateRealscreen.c misccmds.c help.c dec.c inc.c search.c alloc.c \
  211.     updateNextscreen.c mark.c screen.c fileio.c param.c $(MACHSRC)
  212.  
  213. OBJ=    main.o edit.o linefunc.o normal.o cmdline.o charset.o \
  214.     updateRealscreen.o misccmds.o help.o dec.o inc.o search.o alloc.o \
  215.     updateNextscreen.o mark.o screen.o fileio.o param.o $(MACHOBJ)
  216.  
  217. all : stevie
  218.  
  219. stevie : $(OBJ)
  220.     $(CC) $(OBJ) $(LIBS) $(CFLAGS) -o stevie
  221.  
  222. lint:
  223.     lint $(LINTFLAGS) $(SRC)
  224.  
  225. clean :
  226.     rm -f *.out *.o core stevie *.BAK
  227. SHAR_EOF
  228. cat << \SHAR_EOF > makefile.os2
  229. #
  230. # Makefile for OS/2
  231. #
  232. # The make command with OS/2 is really stupid.
  233. #
  234.  
  235. LIBS = ..\regexp\regexp.obj ..\regexp\regsub.obj
  236.  
  237. #
  238. # Compact model lets us edit large files, but keep small model code
  239. #
  240. MODEL= -AC
  241. CFLAGS = $(MODEL) -I..\regexp
  242.  
  243. MACH=    os2.obj
  244.  
  245. OBJ=    main.obj edit.obj linefunc.obj normal.obj cmdline.obj charset.obj \
  246.     updateRealscreen.obj \
  247.     misccmds.obj help.obj dec.obj inc.obj search.obj alloc.obj \
  248.     updateNextscreen.obj mark.obj screen.obj fileio.obj param.obj $(MACH)
  249.  
  250. main.obj:    main.c
  251.     cl -c $(CFLAGS) main.c
  252.  
  253. updateRealscreen.obj:    nexttoscreen.c
  254.     cl -c $(CFLAGS) updateRealscreen.c
  255.  
  256. alloc.obj : alloc.c
  257.     cl -c $(CFLAGS) alloc.c
  258.  
  259. edit.obj : edit.c
  260.     cl -c $(CFLAGS) edit.c
  261.  
  262. updateNextscreen.obj : filetonext.c
  263.     cl -c $(CFLAGS) updateNextscreen.c
  264.  
  265. linefunc.obj : linefunc.c
  266.     cl -c $(CFLAGS) linefunc.c
  267.  
  268. normal.obj : normal.c
  269.     cl -c $(CFLAGS) normal.c
  270.  
  271. cmdline.obj : cmdline.c
  272.     cl -c $(CFLAGS) cmdline.c
  273.  
  274. charset.obj : charset.c
  275.     cl -c $(CFLAGS) charset.c
  276.  
  277. misccmds.obj : misccmds.c
  278.     cl -c $(CFLAGS) misccmds.c
  279.  
  280. help.obj : help.c
  281.     cl -c $(CFLAGS) help.c
  282.  
  283. dec.obj : dec.c
  284.     cl -c $(CFLAGS) dec.c
  285.  
  286. inc.obj : inc.c
  287.     cl -c $(CFLAGS) inc.c
  288.  
  289. search.obj : search.c
  290.     cl -c $(CFLAGS) search.c
  291.  
  292. mark.obj : mark.c
  293.     cl -c $(CFLAGS) mark.c
  294.  
  295. screen.obj : screen.c
  296.     cl -c $(CFLAGS) screen.c
  297.  
  298. fileio.obj : fileio.c
  299.     cl -c $(CFLAGS) fileio.c
  300.  
  301. param.obj : param.c
  302.     cl -c $(CFLAGS) param.c
  303.  
  304. os2.obj : os2.c
  305.     cl -c $(CFLAGS) os2.c
  306.  
  307. stevie.exe : $(OBJ)
  308.     cl $(MODEL) *.obj $(LIBS) -o stevie.exe
  309.     copy stevie.exe rstevie.exe
  310.     bind rstevie.exe \lib\api.lib \lib\doscalls.lib
  311. SHAR_EOF
  312. cat << \SHAR_EOF > makefile.tos
  313. #
  314. # Makefile for the Atari ST - Megamax C compiler
  315. #
  316.  
  317. LIBS = \megamax\regexp.lib
  318.  
  319. CFLAGS = -DMEGAMAX
  320.  
  321. #    Megamax rule
  322. .c.o:
  323.     mmcc $(CFLAGS) $<
  324.     mmimp $*.o
  325.     mmlib rv vi.lib $*.o
  326.  
  327. MACH=    tos.o
  328.  
  329. OBJ=    main.o edit.o linefunc.o normal.o cmdline.o charset.o \
  330.     updateRealscreen.o misccmds.o help.o dec.o inc.o search.o alloc.o \
  331.     updateNextscreen.o mark.o screen.o fileio.o param.o $(MACH)
  332.  
  333. all : stevie.ttp
  334.  
  335. stevie.ttp : $(OBJ)
  336.     $(LINKER) vi.lib $(LIBS) -o stevie.ttp
  337.  
  338. clean :
  339.     $(RM) $(OBJ) vi.lib
  340. SHAR_EOF
  341. cat << \SHAR_EOF > makefile.usg
  342. #
  343. # Makefile for UNIX (System V)
  344. #
  345.  
  346. LIBS = ../regexp/regexp.a
  347. LDFLAGS=
  348.  
  349. CFLAGS = -I../regexp -O
  350.  
  351. MACH=    unix.o
  352.  
  353. OBJ=    main.o edit.o linefunc.o normal.o cmdline.o charset.o \
  354.     updateRealscreen.o misccmds.o help.o dec.o inc.o search.o alloc.o \
  355.     updateNextscreen.o mark.o screen.o fileio.o param.o $(MACH)
  356.  
  357. all : stevie
  358.  
  359. stevie : $(OBJ)
  360.     $(CC) $(OBJ) $(LIBS) -o stevie
  361.  
  362. clean :
  363.     rm $(OBJ)
  364. SHAR_EOF
  365. cat << \SHAR_EOF > os2.c
  366. /*
  367.  * OS/2 System-dependent routines. 
  368.  */
  369.  
  370. #include "stevie.h"
  371.  
  372. /*
  373.  * inchar() - get a character from the keyboard 
  374.  */
  375. char
  376. inchar()
  377. {
  378.     int             c;
  379.  
  380.     flushbuf();            /* flush any pending output */
  381.  
  382.     c = getch();
  383.     if (c == EOF)        /* EOF used like \n, so just assign it */
  384.     c = '\n';
  385.  
  386.     return ((char) c);
  387. }
  388.  
  389. #define    BSIZE    2048
  390. static char     outbuf[BSIZE];
  391. static int      bpos = 0;
  392.  
  393. flushbuf()
  394. {
  395.     if (bpos != 0)
  396.     write(1, outbuf, bpos);
  397.     bpos = 0;
  398. }
  399.  
  400. /*
  401.  * Macro to output a character. Used within this file for speed. 
  402.  */
  403. #define    outone(c)    outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf()
  404.  
  405. /*
  406.  * Function version for use outside this file. 
  407.  */
  408. void
  409. outchar(c)
  410.     char            c;
  411. {
  412.     outbuf[bpos++] = c;
  413.     if (bpos >= BSIZE)
  414.     flushbuf();
  415. }
  416.  
  417. void
  418. outstr(s)
  419.     char           *s;
  420. {
  421.     while (*s) {
  422.     outone(*s++);
  423.     }
  424. }
  425.  
  426. void
  427. beep()
  428. {
  429.     if (RedrawingDisabled)
  430.     return;
  431.  
  432.     outone('\007');
  433. }
  434.  
  435. sleep(n)
  436.     int             n;
  437. {
  438.     extern far pascal DOSSLEEP();
  439.  
  440.     DOSSLEEP(1000L * n);
  441. }
  442.  
  443. void
  444. delay()
  445. {
  446.     DOSSLEEP(500L);
  447. }
  448.  
  449. void
  450. windinit()
  451. {
  452.     Columns = 80;
  453.     P(P_LI) = Rows = 25;
  454. }
  455.  
  456. void
  457. windexit(r)
  458.     int             r;
  459. {
  460.     flushbuf();
  461.     exit(r);
  462. }
  463.  
  464. void
  465. windgoto(r, c)
  466.     int             r, c;
  467. {
  468.     r += 1;
  469.     c += 1;
  470.  
  471.     /*
  472.      * Check for overflow once, to save time. 
  473.      */
  474.     if (bpos + 8 >= BSIZE)
  475.     flushbuf();
  476.  
  477.     outbuf[bpos++] = '\033';
  478.     outbuf[bpos++] = '[';
  479.     if (r >= 10)
  480.     outbuf[bpos++] = r / 10 + '0';
  481.     outbuf[bpos++] = r % 10 + '0';
  482.     outbuf[bpos++] = ';';
  483.     if (c >= 10)
  484.     outbuf[bpos++] = c / 10 + '0';
  485.     outbuf[bpos++] = c % 10 + '0';
  486.     outbuf[bpos++] = 'H';
  487. }
  488.  
  489. FILE           *
  490. fopenb(fname, mode)
  491.     char           *fname;
  492.     char           *mode;
  493. {
  494.     FILE           *fopen();
  495.     char            modestr[16];
  496.  
  497.     sprintf(modestr, "%sb", mode);
  498.     return fopen(fname, modestr);
  499. }
  500. SHAR_EOF
  501. cat << \SHAR_EOF > os2.h
  502. /*
  503.  * OS2 Machine-dependent routines. 
  504.  */
  505. char inchar();
  506. void outchar();
  507. void outstr(), beep();
  508. void windinit(), windexit(), windgoto();
  509. void delay();
  510. void sleep();
  511. SHAR_EOF
  512. cat << \SHAR_EOF > porting.doc
  513.  
  514.          Release Notes for STEVIE - Version 3.10a
  515.  
  516.                    Porting
  517.  
  518.              Tony Andrews -  March 6, 1988
  519.  
  520.  
  521.     Porting the editor is a relatively simple task. Most of the
  522. code is pretty machine-independent. For each environment, there is
  523. a file of routines that perform various low-level operations that
  524. tend to vary a lot from one machine to another. Another file contains
  525. the escape sequences to be used for each machine.
  526.  
  527.     The machine-dependent files currently used are:
  528.  
  529. tos.c:     Atari ST - ifdef for either Megamax or Alcyon
  530. tos.h
  531.  
  532. unix.c:     UNIX System V
  533. unix.h
  534.  
  535. os2.c:     Microsoft OS/2
  536. os2.h
  537.  
  538. amiga.c: Amiga
  539. amiga.h
  540.  
  541. bsd.c:   BSD 4.3 UNIX
  542. bsd.h
  543.  
  544.     Each of these files are around 150 lines long and deal with
  545. low-level issues like character I/O to the terminal, terminal
  546. initialization, cursor addressing, and so on. There are different
  547. tradeoffs to be made depending on the environment. For example, the
  548. UNIX version buffers terminal output because of the relatively high
  549. overhead of system calls. A quick look at the files will make it clear
  550. what needs to be done in a new environment.
  551.  
  552.     Terminal escape sequences are in the file "term.h". These are
  553. defined statically, for the time being. There is some discussion in
  554. term.h regarding which sequences are optional and which are not. The
  555. editor is somewhat flexible in dealing with a lack of terminal
  556. capabilities.
  557.  
  558.     The character set is in the file "charset.c".
  559.  
  560.     Because not all C compilers support command line macro definitions,
  561. the #define's for system-specific macros are placed at the beginning of the
  562. file 'stevie.h'. If you port to a new system, add another line there to
  563. define the macro you choose for your port.
  564.  
  565.     The basic process for doing a new port is:
  566.  
  567.     1. Come up with a macro name to use when ifdef'ing your system-
  568.        specific changes. Add a line at the top of 'stevie.h' to define
  569.        the macro name you've chosen.
  570.  
  571.     2. Look at amiga.c, bsd.c, unix.c, tos.c, and os2.c and copy the one
  572.        that comes closest to working on your system. Then modify your new
  573.        file as needed.
  574.  
  575.     3. Look at term.h and edit the file appropriately adding a new
  576.        set of escape sequence definitions for your system.
  577.  
  578.     4. If you haven't already, get a copy of Henry Spencer's regular
  579.        expression library and compile it. This has been very simple
  580.        every time I've done it.
  581.  
  582.     5. Compiling and debug the editor.
  583. SHAR_EOF
  584. cat << \SHAR_EOF > tos.c
  585. /*
  586.  * System-dependent routines for the Atari ST. 
  587.  */
  588.  
  589. #include "stevie.h"
  590.  
  591. #include <osbind.h>
  592.  
  593. /*
  594.  * The following buffer is used to work around a bug in TOS. It appears that
  595.  * unread console input can cause a crash, but only if console output is
  596.  * going on. The solution is to always grab any unread input before putting
  597.  * out a character. The following buffer holds any characters read in this
  598.  * fashion. The problem can be easily produced because STEVIE can't yet keep
  599.  * up with the normal auto-repeat rate in insert mode. 
  600.  */
  601. #define    IBUFSZ    128
  602.  
  603. static long     inbuf[IBUFSZ];    /* buffer for unread input */
  604. static long    *inptr = inbuf;    /* where to put next character */
  605.  
  606. /*
  607.  * inchar() - get a character from the keyboard 
  608.  *
  609.  * Certain special keys are mapped to values above 0x80. These mappings are
  610.  * defined in keymap.h. If the key has a non-zero ascii value, it is simply
  611.  * returned. Otherwise it may be a special key we want to map. 
  612.  *
  613.  * The ST has a bug involving keyboard input that seems to occur when typing
  614.  * quickly, especially typing capital letters. Sometimes a value of
  615.  * 0x02540000 is read. This doesn't correspond to anything on the keyboard,
  616.  * according to my documentation. My solution is to loop when any unknown key
  617.  * is seen. Normally, the bell is rung to indicate the error. If the "bug"
  618.  * value is seen, we ignore it completely. 
  619.  */
  620. char
  621. inchar()
  622. {
  623.     for (;;) {
  624.     long            c, *p;
  625.  
  626.     /*
  627.      * Get the next input character, either from the input buffer or
  628.      * directly from TOS. 
  629.      */
  630.     if (inptr != inbuf) {    /* input in the buffer, use it */
  631.         c = inbuf[0];
  632.         /*
  633.          * Shift everything else in the buffer down. This would be
  634.          * cleaner if we used a circular buffer, but it really isn't
  635.          * worth it. 
  636.          */
  637.         inptr--;
  638.         for (p = inbuf; p < inptr; p++)
  639.         *p = *(p + 1);
  640.     } else
  641.         c = Crawcin();
  642.  
  643.     if ((c & 0xff) != 0)
  644.         return ((char) c);
  645.  
  646.     switch ((int) (c >> 16) & 0xff) {
  647.  
  648.       case 0x62:
  649.         return K_HELP;
  650.       case 0x61:
  651.         return K_UNDO;
  652.       case 0x52:
  653.         return K_INSERT;
  654.       case 0x47:
  655.         return K_HOME;
  656.       case 0x48:
  657.         return K_UARROW;
  658.       case 0x50:
  659.         return K_DARROW;
  660.       case 0x4b:
  661.         return K_LARROW;
  662.       case 0x4d:
  663.         return K_RARROW;
  664.       case 0x29:
  665.         return K_CGRAVE;    /* control grave accent */
  666.  
  667.         /*
  668.          * Occurs due to a bug in TOS. 
  669.          */
  670.       case 0x54:
  671.         break;
  672.         /*
  673.          * Add the function keys here later if we put in support for
  674.          * macros. 
  675.          */
  676.  
  677.       default:
  678.         beep();
  679.         break;
  680.  
  681.     }
  682.     }
  683. }
  684.  
  685. /*
  686.  * get_inchars - snarf away any pending console input 
  687.  *
  688.  * If the buffer overflows, we discard what's left and ring the bell. 
  689.  */
  690. static void
  691. get_inchars()
  692. {
  693.     while (Cconis()) {
  694.     if (inptr >= &inbuf[IBUFSZ]) {    /* no room in buffer? */
  695.         Crawcin();        /* discard the input */
  696.         beep();        /* and sound the alarm */
  697.     } else
  698.         *inptr++ = Crawcin();
  699.     }
  700. }
  701.  
  702. void
  703. outchar(c)
  704.     char            c;
  705. {
  706.     get_inchars();
  707.     Cconout(c);
  708. }
  709.  
  710. void
  711. outstr(s)
  712.     char           *s;
  713. {
  714.     get_inchars();
  715.     Cconws(s);
  716. }
  717.  
  718. #define    BGND    0
  719. #define    TEXT    3
  720.  
  721. /*
  722.  * vbeep() - visual bell 
  723.  */
  724. static void
  725. vbeep()
  726. {
  727.     int             text, bgnd;    /* text and background colors */
  728.     long            l;
  729.  
  730.     text = Setcolor(TEXT, -1);
  731.     bgnd = Setcolor(BGND, -1);
  732.  
  733.     Setcolor(TEXT, bgnd);    /* swap colors */
  734.     Setcolor(BGND, text);
  735.  
  736.     for (l = 0; l < 5000; l++);    /* short pause */
  737.  
  738.     Setcolor(TEXT, text);    /* restore colors */
  739.     Setcolor(BGND, bgnd);
  740. }
  741.  
  742. void
  743. beep()
  744. {
  745.     if (RedrawingDisabled)
  746.     return;
  747.  
  748.     if (P(P_VB))
  749.     vbeep();
  750.     else
  751.     outchar('\007');
  752. }
  753.  
  754. /*
  755.  * remove(file) - remove a file 
  756.  */
  757. void
  758. remove(file)
  759.     char           *file;
  760. {
  761.     Fdelete(file);
  762. }
  763.  
  764. /*
  765.  * rename(of, nf) - rename existing file 'of' to 'nf' 
  766.  */
  767. void
  768. rename(of, nf)
  769.     char           *of, *nf;
  770. {
  771.     Fdelete(nf);        /* if 'nf' exists, remove it */
  772.     Frename(0, of, nf);
  773. }
  774.  
  775. void
  776. windinit()
  777. {
  778.     if (Getrez() == 0)
  779.     Columns = 40;        /* low resolution */
  780.     else
  781.     Columns = 80;        /* medium or high */
  782.  
  783.     P(P_LI) = Rows = 25;
  784.  
  785.     Cursconf(1, NULL);
  786. }
  787.  
  788. void
  789. windexit(r)
  790.     int             r;
  791. {
  792.     exit(r);
  793. }
  794.  
  795. void
  796. windgoto(r, c)
  797.     int             r, c;
  798. {
  799.     outstr("\033Y");
  800.     outchar(r + 040);
  801.     outchar(c + 040);
  802. }
  803.  
  804. /*
  805.  * System calls or library routines missing in TOS. 
  806.  */
  807.  
  808. void
  809. sleep(n)
  810.     int             n;
  811. {
  812.     int             k;
  813.  
  814.     k = Tgettime();
  815.     while (Tgettime() <= k + n);
  816. }
  817.  
  818. void
  819. delay()
  820. {
  821.     long            n;
  822.  
  823.     for (n = 0; n < 8000; n++);
  824. }
  825.  
  826. int
  827. system(cmd)
  828.     char           *cmd;
  829. {
  830.     char            arg[1];
  831.  
  832.     arg[0] = (char) 0;        /* no arguments passed to the shell */
  833.  
  834.     if (Pexec(0, cmd, arg, 0L) < 0)
  835.     return -1;
  836.     else
  837.     return 0;
  838. }
  839.  
  840. #ifdef    MEGAMAX
  841. char           *
  842. strchr(s, c)
  843.     char           *s;
  844.     int             c;
  845. {
  846.     do {
  847.     if (*s == c)
  848.         return (s);
  849.     } while (*s++);
  850.     return (NULL);
  851. }
  852. #endif
  853.  
  854. #ifdef    MEGAMAX
  855.  
  856. FILE           *
  857. fopenb(fname, mode)
  858.     char           *fname;
  859.     char           *mode;
  860. {
  861.     char            modestr[10];
  862.  
  863.     sprintf(modestr, "b%s", mode);
  864.  
  865.     return fopen(fname, modestr);
  866. }
  867.  
  868. #endif
  869.  
  870. /*
  871.  * getenv() - get a string from the environment 
  872.  *
  873.  * Both Alcyon and Megamax are missing getenv(). This routine works for both
  874.  * compilers and with the Beckemeyer and Gulam shells. With gulam, the
  875.  * env_style variable should be set to either "mw" or "gu". 
  876.  */
  877. char           *
  878. getenv(name)
  879.     char           *name;
  880. {
  881.     extern long     _base;
  882.     char           *envp, *p;
  883.  
  884.     envp = *((char **) (_base + 0x2c));
  885.  
  886.     for (; *envp; envp += strlen(envp) + 1) {
  887.     if (strncmp(envp, name, strlen(name)) == 0) {
  888.         p = envp + strlen(name);
  889.         if (*p++ == '=')
  890.         return p;
  891.     }
  892.     }
  893.     return (char *) 0;
  894. }
  895. SHAR_EOF
  896. cat << \SHAR_EOF > tos.h
  897. /*
  898.  * Atari Machine-dependent routines. 
  899.  */
  900. char inchar();
  901. void outchar();
  902. void outstr(), beep();
  903. void remove(), rename();
  904. void windinit(), windexit(), windgoto();
  905. void delay();
  906. void sleep();
  907. SHAR_EOF
  908. cat << \SHAR_EOF > unix.c
  909. /*
  910.  * System-dependent routines for UNIX System V Release 3. 
  911.  */
  912.  
  913. #include "stevie.h"
  914. /* #include <termio.h> /* System V */
  915. #include <curses.h>        /* BSD */
  916.  
  917. /*
  918.  * inchar() - get a character from the keyboard 
  919.  */
  920. char
  921. inchar()
  922. {
  923.     char            c;
  924.  
  925.     flushbuf();            /* flush any pending output */
  926.  
  927.     while (read(0, &c, 1) != 1);
  928.  
  929.     return c;
  930. }
  931.  
  932. #define    BSIZE    2048
  933. static char     outbuf[BSIZE];
  934. static int      bpos = 0;
  935.  
  936. flushbuf()
  937. {
  938.     if (bpos != 0)
  939.     write(1, outbuf, bpos);
  940.     bpos = 0;
  941. }
  942.  
  943. /*
  944.  * Macro to output a character. Used within this file for speed. 
  945.  */
  946. #define    outone(c)    outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf()
  947.  
  948. /*
  949.  * Function version for use outside this file. 
  950.  */
  951. void
  952. outchar(c)
  953.     char            c;
  954. {
  955.     outbuf[bpos++] = c;
  956.     if (bpos >= BSIZE)
  957.     flushbuf();
  958. }
  959.  
  960. void
  961. outstr(s)
  962.     char           *s;
  963. {
  964.     while (*s) {
  965.     outone(*s++);
  966.     }
  967. }
  968.  
  969. void
  970. beep()
  971. {
  972.     if (RedrawingDisabled)
  973.     return;
  974.  
  975.     outone('\007');
  976. }
  977.  
  978. /*
  979.  * remove(file) - remove a file 
  980.  */
  981. void
  982. remove(file)
  983.     char           *file;
  984. {
  985.     unlink(file);
  986. }
  987.  
  988. /*
  989.  * rename(of, nf) - rename existing file 'of' to 'nf' 
  990.  */
  991. void
  992. rename(of, nf)
  993.     char           *of, *nf;
  994. {
  995.     unlink(nf);
  996.     link(of, nf);
  997.     unlink(of);
  998. }
  999.  
  1000. void
  1001. delay()
  1002. {
  1003.     /* not implemented */
  1004. }
  1005.  
  1006. static struct termio ostate;
  1007.  
  1008. void
  1009. windinit()
  1010. {
  1011.     char           *getenv();
  1012.     char           *term;
  1013.     struct termio   nstate;
  1014.  
  1015.     if ((term = getenv("TERM")) == NULL || strcmp(term, "vt100") != 0) {
  1016.     fprintf(stderr, "Invalid terminal type '%s'\n", term);
  1017.     exit(1);
  1018.     }
  1019.     Columns = 80;
  1020.     P(P_LI) = Rows = 24;
  1021.  
  1022.     /*
  1023.      * Go into cbreak mode 
  1024.      */
  1025.     ioctl(0, TCGETA, &ostate);
  1026.     nstate = ostate;
  1027.     nstate.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
  1028.     nstate.c_cc[VMIN] = 1;
  1029.     nstate.c_cc[VTIME] = 0;
  1030.     ioctl(0, TCSETAW, &nstate);
  1031. }
  1032.  
  1033. void
  1034. windexit(r)
  1035.     int             r;
  1036. {
  1037.     /*
  1038.      * Restore terminal modes 
  1039.      */
  1040.     ioctl(0, TCSETAW, &ostate);
  1041.  
  1042.     exit(r);
  1043. }
  1044.  
  1045. #define    outone(c)    outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf()
  1046.  
  1047. void
  1048. windgoto(r, c)
  1049.     int             r, c;
  1050. {
  1051.     r += 1;
  1052.     c += 1;
  1053.  
  1054.     /*
  1055.      * Check for overflow once, to save time. 
  1056.      */
  1057.     if (bpos + 8 >= BSIZE)
  1058.     flushbuf();
  1059.  
  1060.     outbuf[bpos++] = '\033';
  1061.     outbuf[bpos++] = '[';
  1062.     if (r >= 10)
  1063.     outbuf[bpos++] = r / 10 + '0';
  1064.     outbuf[bpos++] = r % 10 + '0';
  1065.     outbuf[bpos++] = ';';
  1066.     if (c >= 10)
  1067.     outbuf[bpos++] = c / 10 + '0';
  1068.     outbuf[bpos++] = c % 10 + '0';
  1069.     outbuf[bpos++] = 'H';
  1070. }
  1071.  
  1072. FILE           *
  1073. fopenb(fname, mode)
  1074.     char           *fname;
  1075.     char           *mode;
  1076. {
  1077.     return fopen(fname, mode);
  1078. }
  1079. SHAR_EOF
  1080. cat << \SHAR_EOF > unix.h
  1081. /*
  1082.  * Unix Machine-dependent routines. 
  1083.  */
  1084. char inchar();
  1085. void outchar();
  1086. void outstr(), beep();
  1087. void remove(), rename();
  1088. void windinit(), windexit(), windgoto();
  1089. void delay();
  1090. SHAR_EOF
  1091. cat << \SHAR_EOF > normal.c
  1092. /*
  1093.  * STEVIE - Simply Try this Editor for VI Enthusiasts
  1094.  *
  1095.  * Code Contributions By : Tim Thompson           twitch!tjt
  1096.  *                         Tony Andrews           onecom!wldrdg!tony 
  1097.  *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  1098.  */
  1099.  
  1100. /*
  1101.  * This file contains the main routine for processing characters in command
  1102.  * mode as well as routines for handling the operators. 
  1103.  */
  1104.  
  1105. #include "stevie.h"
  1106.  
  1107. static void
  1108. doshift(), dodelete(), doput(), dochange();
  1109. static void
  1110.                 startinsert();
  1111. static          bool_t
  1112.                 dojoin();
  1113. static          bool_t
  1114.                 doyank();
  1115.  
  1116. /*
  1117.  * Macro evaluates true if char 'c' is a valid identifier character 
  1118.  */
  1119. #define    IDCHAR(c)    (isalpha(c) || isdigit(c) || (c) == '_')
  1120.  
  1121. /*
  1122.  * Operators 
  1123.  */
  1124. #define    NOP    0        /* no pending operation */
  1125. #define    DELETE    1
  1126. #define    YANK    2
  1127. #define    CHANGE    3
  1128. #define    LSHIFT    4
  1129. #define    RSHIFT    5
  1130.  
  1131. #define    CLEAROP    (operator = NOP)/* clear any pending operator */
  1132.  
  1133. static int      operator = NOP;    /* current pending operator */
  1134.  
  1135. /*
  1136.  * When a cursor motion command is made, it is marked as being a character or
  1137.  * line oriented motion. Then, if an operator is in effect, the operation
  1138.  * becomes character or line oriented accordingly. 
  1139.  *
  1140.  * Character motions are marked as being inclusive or not. Most char. motions
  1141.  * are inclusive, but some (e.g. 'w') are not. 
  1142.  *
  1143.  * Generally speaking, every command in normal() should either clear any pending
  1144.  * operator (with CLEAROP), or set the motion type variable. 
  1145.  */
  1146.  
  1147. /*
  1148.  * Motion types 
  1149.  */
  1150. #define    MBAD    (-1)        /* 'bad' motion type marks unusable yank buf */
  1151. #define    MCHAR    0
  1152. #define    MLINE    1
  1153.  
  1154. static int      mtype;        /* type of the current cursor motion */
  1155. static bool_t   mincl;        /* true if char motion is inclusive */
  1156. static int      ybtype = MBAD;
  1157. static int      ybcrossline = FALSE;
  1158.  
  1159. static LPTR     startop;    /* cursor pos. at start of operator */
  1160.  
  1161. /*
  1162.  * Operators can have counts either before the operator, or between the
  1163.  * operator and the following cursor motion as in: 
  1164.  *
  1165.  * d3w or 3dw 
  1166.  *
  1167.  * If a count is given before the operator, it is saved in opnum. If normal() is
  1168.  * called with a pending operator, the count in opnum (if present) overrides
  1169.  * any count that came later. 
  1170.  */
  1171. static int      opnum = 0;
  1172.  
  1173. #define    DEFAULT1(x)    (((x) == 0) ? 1 : (x))
  1174.  
  1175. /*
  1176.  * normal 
  1177.  *
  1178.  * Execute a command in normal mode. 
  1179.  */
  1180.  
  1181. void
  1182. normal(c)
  1183.     char            c;
  1184. {
  1185.     char           *p;
  1186.     int             n;
  1187.     int             nn;
  1188.     bool_t          flag = FALSE;
  1189.     int             type = 0;    /* used in some operations to modify type */
  1190.     int             dir = FORWARD;    /* search direction */
  1191.     char            nchar = NUL;
  1192.     bool_t          finish_op;
  1193.     LPTR            temp_Curschar;
  1194.  
  1195.     last_command = NUL;
  1196.     /*
  1197.      * If there is an operator pending, then the command we take this time
  1198.      * will terminate it. Finish_op tells us to finish the operation before
  1199.      * returning this time (unless the operation was cancelled). 
  1200.      */
  1201.     finish_op = (operator != NOP);
  1202.  
  1203.     /*
  1204.      * If we're in the middle of an operator AND we had a count before the
  1205.      * operator, then that count overrides the current value of Prenum. What
  1206.      * this means effectively, is that commands like "3dw" get turned into
  1207.      * "d3w" which makes things fall into place pretty neatly. 
  1208.      */
  1209.     if (finish_op) {
  1210.     if (opnum != 0)
  1211.         Prenum = opnum;
  1212.     } else
  1213.     opnum = 0;
  1214.  
  1215.     switch (c) {
  1216.  
  1217.       case K_HELP:
  1218.     CLEAROP;
  1219.     if (help()) {
  1220.         screenclear();
  1221.         updateNextscreen();
  1222.     }
  1223.     break;
  1224.  
  1225.       case CTRL('L'):
  1226.     CLEAROP;
  1227.     screenclear();
  1228.     updateNextscreen();
  1229.     break;
  1230.  
  1231.       case CTRL('D'):
  1232.     CLEAROP;
  1233.     if (Prenum)
  1234.         P(P_SS) = (Prenum > Rows - 1) ? Rows - 1 : Prenum;
  1235.     scrollup((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
  1236.     onedown((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
  1237.     updateNextscreen();
  1238.     break;
  1239.  
  1240.       case CTRL('U'):
  1241.     CLEAROP;
  1242.     if (Prenum)
  1243.         P(P_SS) = (Prenum > Rows - 1) ? Rows - 1 : Prenum;
  1244.     scrolldown((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
  1245.     oneup((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
  1246.     updateNextscreen();
  1247.     break;
  1248.  
  1249.       case CTRL('F'):
  1250.     CLEAROP;
  1251.     if (nextline(Topchar) == NULL) {
  1252.         beep();
  1253.         break;
  1254.     }
  1255.     screenclear();
  1256.     Prenum = DEFAULT1(Prenum);
  1257.     while (Prenum > 0) {
  1258.         *Curschar = *prevline(Botchar);
  1259.         *Topchar = *Curschar;
  1260.         Topchar->index = 0;
  1261.         updateNextscreen();
  1262.         Prenum--;
  1263.     }
  1264.     beginline(TRUE);
  1265.     break;
  1266.  
  1267.       case CTRL('B'):
  1268.     CLEAROP;
  1269.     if (prevline(Topchar) == NULL) {
  1270.         beep();
  1271.         break;
  1272.     }
  1273.     screenclear();
  1274.     Prenum = DEFAULT1(Prenum);
  1275.     while (Prenum > 0) {
  1276.         *Curschar = *Topchar;
  1277.         n = Rows - 1;
  1278.         {
  1279.         LPTR           *lp = Curschar;
  1280.         int             l = 0;
  1281.  
  1282.         while ((l < n) && (lp != NULL)) {
  1283.             l += plines(lp);
  1284.             *Topchar = *lp;
  1285.             lp = prevline(lp);
  1286.         }
  1287.         }
  1288.         Topchar->index = 0;
  1289.         Prenum--;
  1290.     }
  1291.     beginline(TRUE);
  1292.     updateNextscreen();
  1293.     break;
  1294.  
  1295.       case CTRL('E'):
  1296.     CLEAROP;
  1297.     scrollup(DEFAULT1(Prenum));
  1298.     updateNextscreen();
  1299.     break;
  1300.  
  1301.       case CTRL('Y'):
  1302.     CLEAROP;
  1303.     scrolldown(DEFAULT1(Prenum));
  1304.     updateNextscreen();
  1305.     break;
  1306.  
  1307.       case 'z':
  1308.     CLEAROP;
  1309.     switch (vgetc()) {
  1310.       case NL:        /* put Curschar at top of screen */
  1311.       case CR:
  1312.         *Topchar = *Curschar;
  1313.         Topchar->index = 0;
  1314.         updateNextscreen();
  1315.         break;
  1316.  
  1317.       case '.':        /* put Curschar in middle of screen */
  1318.         n = Rows / 2;
  1319.         goto dozcmd;
  1320.  
  1321.       case '-':        /* put Curschar at bottom of screen */
  1322.         n = Rows - 1;
  1323.         /* FALLTHROUGH */
  1324.  
  1325.     dozcmd:
  1326.         {
  1327.         LPTR           *lp = Curschar;
  1328.         int             l = 0;
  1329.  
  1330.         while ((l < n) && (lp != NULL)) {
  1331.             l += plines(lp);
  1332.             *Topchar = *lp;
  1333.             lp = prevline(lp);
  1334.         }
  1335.         }
  1336.         Topchar->index = 0;
  1337.         updateNextscreen();
  1338.         break;
  1339.  
  1340.       default:
  1341.         beep();
  1342.     }
  1343.     break;
  1344.  
  1345.       case CTRL('G'):
  1346.     CLEAROP;
  1347.     fileinfo();
  1348.     break;
  1349.  
  1350.       case 'G':
  1351.     mtype = MLINE;
  1352.     *Curschar = *gotoline(Prenum);
  1353.     beginline(TRUE);
  1354.     break;
  1355.  
  1356.       case 'H':
  1357.     mtype = MLINE;
  1358.     *Curschar = *Topchar;
  1359.     for (n = Prenum; n && onedown(1); n--);
  1360.     beginline(TRUE);
  1361.     break;
  1362.  
  1363.       case 'M':
  1364.     mtype = MLINE;
  1365.     *Curschar = *Topchar;
  1366.     for (n = 0; n < Rows / 2 && onedown(1); n++);
  1367.     beginline(TRUE);
  1368.     break;
  1369.  
  1370.       case 'L':
  1371.     mtype = MLINE;
  1372.     *Curschar = *prevline(Botchar);
  1373.     for (n = Prenum; n && oneup(1); n--);
  1374.     beginline(TRUE);
  1375.     break;
  1376.  
  1377.       case 'l':
  1378.       case K_RARROW:
  1379.       case ' ':
  1380.     mtype = MCHAR;
  1381.     mincl = FALSE;
  1382.     n = DEFAULT1(Prenum);
  1383.     while (n--) {
  1384.         if (!oneright()) {
  1385.         if (operator != DELETE && operator != CHANGE) {
  1386.             beep();
  1387.         } else {
  1388.             if (lineempty(Curschar)) {
  1389.             CLEAROP;
  1390.             beep();
  1391.             } else {
  1392.             mincl = TRUE;
  1393.             }
  1394.         }
  1395.         break;
  1396.         }
  1397.     }
  1398.     set_want_col = TRUE;
  1399.     break;
  1400.  
  1401.       case 'h':
  1402.       case K_LARROW:
  1403.       case CTRL('H'):
  1404.     mtype = MCHAR;
  1405.     mincl = FALSE;
  1406.     Prenum = DEFAULT1(Prenum);
  1407.     n = Prenum;
  1408.     while (n--) {
  1409.         if (!oneleft()) {
  1410.         if (operator != DELETE && operator != CHANGE) {
  1411.             beep();
  1412.         } else if (Prenum == 1) {
  1413.             CLEAROP;
  1414.             beep();
  1415.         }
  1416.         break;
  1417.         }
  1418.     }
  1419.     set_want_col = TRUE;
  1420.     break;
  1421.  
  1422.       case '-':
  1423.     flag = TRUE;
  1424.     /* FALLTHROUGH */
  1425.  
  1426.       case 'k':
  1427.       case K_UARROW:
  1428.       case CTRL('P'):
  1429.     mtype = MLINE;
  1430.     if (!oneup(DEFAULT1(Prenum))) {
  1431.         CLEAROP;
  1432.         beep();
  1433.     } else if (flag)
  1434.         beginline(TRUE);
  1435.     break;
  1436.  
  1437.       case '+':
  1438.       case CR:
  1439.       case NL:
  1440.     flag = TRUE;
  1441.     /* FALLTHROUGH */
  1442.  
  1443.       case 'j':
  1444.       case K_DARROW:
  1445.       case CTRL('N'):
  1446.     mtype = MLINE;
  1447.     if (!onedown(DEFAULT1(Prenum))) {
  1448.         CLEAROP;
  1449.         beep();
  1450.     } else if (flag)
  1451.         beginline(TRUE);
  1452.     break;
  1453.  
  1454.     /*
  1455.      * This is a strange motion command that helps make operators more
  1456.      * logical. It is actually implemented, but not documented in the
  1457.      * real 'vi'. This motion command actually refers to "the current
  1458.      * line". Commands like "dd" and "yy" are really an alternate form of
  1459.      * "d_" and "y_". It does accept a count, so "d3_" works to delete 3
  1460.      * lines. 
  1461.      */
  1462.       case '_':
  1463. lineop:
  1464.     mtype = MLINE;
  1465.     if (!onedown(DEFAULT1(Prenum) - 1)) {
  1466.         CLEAROP;
  1467.         beep();
  1468.     } else
  1469.         beginline(TRUE);
  1470.     break;
  1471.  
  1472.       case '|':
  1473.     mtype = MCHAR;
  1474.     mincl = TRUE;
  1475.     beginline(FALSE);
  1476.     if (Prenum > 0)
  1477.         *Curschar = *coladvance(Curschar, Prenum - 1);
  1478.     Curswant = Prenum - 1;
  1479.     break;
  1480.  
  1481.       case CTRL(']'):        /* :ta to current identifier */
  1482.     CLEAROP;
  1483.     {
  1484.         char            ch;
  1485.         LPTR            save;
  1486.  
  1487.         save = *Curschar;
  1488.         /*
  1489.          * First back up to start of identifier. This doesn't match the
  1490.          * real vi but I like it a little better and it shouldn't bother
  1491.          * anyone. 
  1492.          */
  1493.         ch = gchar(Curschar);
  1494.         while (IDCHAR(ch)) {
  1495.         if (!oneleft())
  1496.             break;
  1497.         ch = gchar(Curschar);
  1498.         }
  1499.         if (!IDCHAR(ch))
  1500.         oneright();
  1501.  
  1502.         stuffReadbuff(":ta ");
  1503.         /*
  1504.          * Now grab the chars in the identifier 
  1505.          */
  1506.         ch = gchar(Curschar);
  1507.         while (IDCHAR(ch)) {
  1508.         stuffReadbuff(mkstr(ch));
  1509.         if (!oneright())
  1510.             break;
  1511.         ch = gchar(Curschar);
  1512.         }
  1513.         stuffReadbuff("\n");
  1514.  
  1515.         *Curschar = save;    /* restore, in case of error */
  1516.     }
  1517.     break;
  1518.  
  1519.       case '%':
  1520.     mtype = MCHAR;
  1521.     mincl = TRUE;
  1522.     {
  1523.         LPTR           *pos;
  1524.  
  1525.         if ((pos = showmatch()) == NULL) {
  1526.         CLEAROP;
  1527.         beep();
  1528.         } else {
  1529.         setpcmark();
  1530.         *Curschar = *pos;
  1531.         set_want_col = TRUE;
  1532.         }
  1533.     }
  1534.     break;
  1535.  
  1536.     /*
  1537.      * Word Motions 
  1538.      */
  1539.  
  1540.       case 'B':
  1541.     type = 1;
  1542.     /* FALLTHROUGH */
  1543.  
  1544.       case 'b':
  1545.     mtype = MCHAR;
  1546.     mincl = FALSE;
  1547.     set_want_col = TRUE;
  1548.     for (n = DEFAULT1(Prenum); n > 0; n--) {
  1549.         LPTR           *pos;
  1550.  
  1551.         if ((Curschar->linep->prev == NULL) && (Curschar->index == 0)) {
  1552.         CLEAROP;
  1553.         beep();
  1554.         break;
  1555.         }
  1556.         pos = bck_word(Curschar, type);
  1557.         if (pos == NULL)
  1558.         *Curschar = *gotoline(1);    /* goto top of file */
  1559.         else
  1560.         *Curschar = *pos;
  1561.     }
  1562.     break;
  1563.  
  1564.       case 'W':
  1565.     type = 1;
  1566.     /* FALLTHROUGH */
  1567.  
  1568.       case 'w':
  1569.     /*
  1570.      * This is a little strange. To match what the real vi does, we
  1571.      * effectively map 'cw' to 'ce', and 'cW' to 'cE'. This seems
  1572.      * impolite at first, but it's really more what we mean when we say
  1573.      * 'cw'. 
  1574.      */
  1575.     if (operator == CHANGE)
  1576.         goto doecmd;
  1577.  
  1578.     mtype = MCHAR;
  1579.     mincl = FALSE;
  1580.     set_want_col = TRUE;
  1581.     for (n = DEFAULT1(Prenum); n > 0; n--) {
  1582.         LPTR           *pos;
  1583.  
  1584.         if ((pos = fwd_word(Curschar, type)) == NULL) {
  1585.         CLEAROP;
  1586.         beep();
  1587.         break;
  1588.         } else
  1589.         *Curschar = *pos;
  1590.     }
  1591.     break;
  1592.  
  1593.       case 'E':
  1594.     type = 1;
  1595.     /* FALLTHROUGH */
  1596.  
  1597.       case 'e':
  1598. doecmd:
  1599.     mtype = MCHAR;
  1600.     mincl = TRUE;
  1601.     set_want_col = TRUE;
  1602.     for (n = DEFAULT1(Prenum); n > 0; n--) {
  1603.         LPTR           *pos;
  1604.  
  1605.         if ((pos = end_word(Curschar, type)) == NULL) {
  1606.         CLEAROP;
  1607.         beep();
  1608.         break;
  1609.         } else
  1610.         *Curschar = *pos;
  1611.     }
  1612.     break;
  1613.  
  1614.       case '$':
  1615.     mtype = MCHAR;
  1616.     mincl = TRUE;
  1617.     while (oneright());
  1618.     Curswant = 999;        /* so we stay at the end */
  1619.     break;
  1620.  
  1621.       case '^':
  1622.     flag = TRUE;
  1623.     /* FALLTHROUGH */
  1624.  
  1625.       case '0':
  1626.     mtype = MCHAR;
  1627.     mincl = TRUE;
  1628.     beginline(flag);
  1629.     break;
  1630.  
  1631.       case 'A':
  1632.     set_want_col = TRUE;
  1633.     while (oneright());
  1634.     ResetBuffers();
  1635.     AppendToRedobuff("A");
  1636.     goto doAPPENDcmd;
  1637.  
  1638.       case 'a':
  1639.     ResetBuffers();
  1640.     AppendToRedobuff("a");
  1641.  
  1642. doAPPENDcmd:
  1643.     CLEAROP;
  1644.     /* Works just like an 'i'nsert on the next character. */
  1645.     n = RowNumber(Curschar);
  1646.     AppendPositionToUndoUndobuff(Curschar->index, n);
  1647.     AppendToUndoUndobuff("a");
  1648.  
  1649.     if (!lineempty(Curschar))
  1650.         inc(Curschar);
  1651.  
  1652.     n = RowNumber(Curschar);
  1653.     AppendPositionToUndobuff(Curschar->index, n);
  1654.  
  1655.     startinsert(FALSE);
  1656.  
  1657.     CHANGED;
  1658.     break;
  1659.  
  1660.       case 'I':
  1661.     beginline(TRUE);
  1662.     ResetBuffers();
  1663.     AppendToRedobuff("I");
  1664.     goto doINSERTcmd;
  1665.     /* FALLTHROUGH */
  1666.  
  1667.       case 'i':
  1668.       case K_INSERT:
  1669.     ResetBuffers();
  1670.     AppendToRedobuff("i");
  1671.  
  1672. doINSERTcmd:
  1673.     CLEAROP;
  1674.  
  1675.     n = RowNumber(Curschar);
  1676.     AppendPositionToUndobuff(Curschar->index, n);
  1677.     AppendPositionToUndoUndobuff(Curschar->index, n);
  1678.     AppendToUndoUndobuff("i");
  1679.  
  1680.     startinsert(FALSE);
  1681.  
  1682.     CHANGED;
  1683.     break;
  1684.  
  1685.       case 'o':
  1686.     CLEAROP;
  1687.     ResetBuffers();
  1688.  
  1689.     n = RowNumber(Curschar);
  1690.     AppendToRedobuff("o");
  1691.     AppendPositionToUndobuff(Curschar->index, n);
  1692.     AppendPositionToUndoUndobuff(Curschar->index, n);
  1693.     AppendToUndoUndobuff("o");
  1694.  
  1695.     if (opencmd(FORWARD, TRUE)) {
  1696.         startinsert(TRUE);
  1697.  
  1698.         CHANGED;
  1699.     }
  1700.     last_command = 'o';
  1701.     break;
  1702.  
  1703.       case 'O':
  1704.     CLEAROP;
  1705.     ResetBuffers();
  1706.  
  1707.     n = RowNumber(Curschar);
  1708.     AppendToRedobuff("O");
  1709.     AppendPositionToUndobuff(Curschar->index, n);
  1710.     AppendPositionToUndoUndobuff(Curschar->index, n);
  1711.     AppendToUndoUndobuff("O");
  1712.  
  1713.     if (opencmd(BACKWARD, TRUE)) {
  1714.         startinsert(TRUE);
  1715.  
  1716.         CHANGED;
  1717.     }
  1718.     last_command = 'O';
  1719.     break;
  1720.  
  1721.       case 'd':
  1722.     if (operator == DELETE)    /* handle 'dd' */
  1723.         goto lineop;
  1724.     if (Prenum != 0)
  1725.         opnum = Prenum;
  1726.     startop = *Curschar;
  1727.     operator = DELETE;
  1728.     break;
  1729.  
  1730.     /*
  1731.      * Some convenient abbreviations... 
  1732.      */
  1733.  
  1734.       case 'x':
  1735.     if (Prenum)
  1736.         stuffnumReadbuff(Prenum);
  1737.     stuffReadbuff("dl");
  1738.     break;
  1739.  
  1740.       case 'X':
  1741.     if (Prenum)
  1742.         stuffnumReadbuff(Prenum);
  1743.     stuffReadbuff("dh");
  1744.     break;
  1745.  
  1746.       case 'D':
  1747.     stuffReadbuff("d$");
  1748.     break;
  1749.  
  1750.       case 'Y':
  1751.     if (Prenum)
  1752.         stuffnumReadbuff(Prenum);
  1753.     stuffReadbuff("yy");
  1754.     break;
  1755.  
  1756.       case 'C':
  1757.     stuffReadbuff("c$");
  1758.     break;
  1759.  
  1760.       case 'c':
  1761.     if (operator == CHANGE) {    /* handle 'cc' */
  1762.         CLEAROP;
  1763.         stuffReadbuff("0c$");
  1764.         break;
  1765.     }
  1766.     if (Prenum != 0)
  1767.         opnum = Prenum;
  1768.     startop = *Curschar;
  1769.     operator = CHANGE;
  1770.     break;
  1771.  
  1772.       case 'y':
  1773.     if (operator == YANK)    /* handle 'yy' */
  1774.         goto lineop;
  1775.     if (Prenum != 0)
  1776.         opnum = Prenum;
  1777.     startop = *Curschar;
  1778.     operator = YANK;
  1779.     break;
  1780.  
  1781.       case 'p':
  1782.     if (RedrawingDisabled) {
  1783.         RedrawingDisabled = FALSE;
  1784.         updateNextscreen();
  1785.         break;
  1786.     } else if (Yankbuffptr != NULL) {
  1787.         doput(FORWARD);
  1788.  
  1789.         if (ybcrossline) {
  1790.         n = RowNumber(Curschar);
  1791.         stuffnumReadbuff(n);
  1792.         stuffReadbuff("G");
  1793.         if (ybtype == MCHAR) {
  1794.             stuffnumReadbuff(Curschar->index);
  1795.             if (Curschar->index)
  1796.             stuffReadbuff("l");
  1797.         } else
  1798.             stuffnumReadbuff(0);
  1799.         }
  1800.         stuffReadbuff("p");
  1801.         RedrawingDisabled = TRUE;
  1802.     } else
  1803.         beep();
  1804.     break;
  1805.  
  1806.       case 'P':
  1807.     if (RedrawingDisabled) {
  1808.         RedrawingDisabled = FALSE;
  1809.         updateNextscreen();
  1810.         break;
  1811.     } else if (Yankbuffptr != NULL) {
  1812.         doput(BACKWARD);
  1813.  
  1814.         n = RowNumber(Curschar);
  1815.         stuffnumReadbuff(n);
  1816.         stuffReadbuff("G");
  1817.         if (ybtype == MCHAR) {
  1818.         stuffnumReadbuff(Curschar->index);
  1819.         if (Curschar->index)
  1820.             stuffReadbuff("l");
  1821.         } else
  1822.         stuffnumReadbuff(0);
  1823.         stuffReadbuff("P");
  1824.         RedrawingDisabled = TRUE;
  1825.     } else
  1826.         beep();
  1827.     break;
  1828.  
  1829.       case '>':
  1830.     if (operator == RSHIFT)    /* handle >> */
  1831.         goto lineop;
  1832.     if (operator == LSHIFT) {
  1833.         CLEAROP;
  1834.         beep();
  1835.         break;
  1836.     }
  1837.     if (Prenum != 0)
  1838.         opnum = Prenum;
  1839.     startop = *Curschar;    /* save current position */
  1840.     operator = RSHIFT;
  1841.     break;
  1842.  
  1843.       case '<':
  1844.     if (operator == LSHIFT)    /* handle << */
  1845.         goto lineop;
  1846.     if (operator == RSHIFT) {
  1847.         CLEAROP;
  1848.         beep();
  1849.         break;
  1850.     }
  1851.     if (Prenum != 0)
  1852.         opnum = Prenum;
  1853.     startop = *Curschar;    /* save current position */
  1854.     operator = LSHIFT;
  1855.     break;
  1856.  
  1857.       case 's':        /* substitute characters */
  1858.     if (Prenum)
  1859.         stuffnumReadbuff(Prenum);
  1860.     stuffReadbuff("cl");
  1861.     break;
  1862.  
  1863.       case '?':
  1864.       case '/':
  1865.       case ':':
  1866.     CLEAROP;
  1867.     readcmdline(c, (char *) NULL);
  1868.     break;
  1869.  
  1870.       case 'n':
  1871.     mtype = MCHAR;
  1872.     mincl = FALSE;
  1873.     set_want_col = TRUE;
  1874.     repsearch(0);
  1875.     break;
  1876.  
  1877.       case 'N':
  1878.     mtype = MCHAR;
  1879.     mincl = FALSE;
  1880.     set_want_col = TRUE;
  1881.     repsearch(1);
  1882.     break;
  1883.  
  1884.     /*
  1885.      * Character searches 
  1886.      */
  1887.       case 'T':
  1888.     dir = BACKWARD;
  1889.     /* FALLTHROUGH */
  1890.  
  1891.       case 't':
  1892.     type = 1;
  1893.     goto docsearch;
  1894.  
  1895.       case 'F':
  1896.     dir = BACKWARD;
  1897.     /* FALLTHROUGH */
  1898.  
  1899.       case 'f':
  1900. docsearch:
  1901.     mtype = MCHAR;
  1902.     mincl = TRUE;
  1903.     set_want_col = TRUE;
  1904.     if ((nchar = vgetc()) == ESC)    /* search char */
  1905.         break;
  1906.     if (!searchc(nchar, dir, type)) {
  1907.         CLEAROP;
  1908.         beep();
  1909.     }
  1910.     break;
  1911.  
  1912.       case ',':
  1913.     flag = 1;
  1914.     /* FALLTHROUGH */
  1915.  
  1916.       case ';':
  1917.     mtype = MCHAR;
  1918.     mincl = TRUE;
  1919.     set_want_col = TRUE;
  1920.     if (!crepsearch(flag)) {
  1921.         CLEAROP;
  1922.         beep();
  1923.     }
  1924.     break;
  1925.  
  1926.     /*
  1927.      * Function searches 
  1928.      */
  1929.  
  1930.       case '[':
  1931.     dir = BACKWARD;
  1932.     /* FALLTHROUGH */
  1933.  
  1934.       case ']':
  1935.     mtype = MLINE;
  1936.     set_want_col = TRUE;
  1937.     if (vgetc() != c)
  1938.         beep();
  1939.  
  1940.     if (!findfunc(dir)) {
  1941.         CLEAROP;
  1942.         beep();
  1943.     }
  1944.     break;
  1945.  
  1946.     /*
  1947.      * Marks 
  1948.      */
  1949.  
  1950.       case 'm':
  1951.     CLEAROP;
  1952.     if (!setmark(vgetc()))
  1953.         beep();
  1954.     break;
  1955.  
  1956.       case '\'':
  1957.     flag = TRUE;
  1958.     /* FALLTHROUGH */
  1959.  
  1960.       case '`':
  1961.     {
  1962.         LPTR            mtmp, *mark = getmark(vgetc());
  1963.  
  1964.         if (mark == NULL) {
  1965.         CLEAROP;
  1966.         beep();
  1967.         } else {
  1968.         mtmp = *mark;
  1969.         setpcmark();
  1970.         *Curschar = mtmp;
  1971.         if (flag)
  1972.             beginline(TRUE);
  1973.         }
  1974.         mtype = flag ? MLINE : MCHAR;
  1975.         mincl = TRUE;    /* ignored if not MCHAR */
  1976.         set_want_col = TRUE;
  1977.     }
  1978.     break;
  1979.  
  1980.       case 'r':
  1981.     CLEAROP;
  1982.     if (lineempty(Curschar)) {    /* Nothing to replace */
  1983.         beep();
  1984.         break;
  1985.     }
  1986.     if ((nchar = vgetc()) == ESC)
  1987.         break;
  1988.  
  1989.     Prenum = DEFAULT1(Prenum);
  1990.     n = strlen(Curschar->linep->s) - Curschar->index;
  1991.     if (n < Prenum) {
  1992.         beep();
  1993.         break;
  1994.     }
  1995.     ResetBuffers();
  1996.  
  1997.     nn = RowNumber(Curschar);
  1998.     AppendPositionToUndobuff(Curschar->index, nn);
  1999.     AppendPositionToUndoUndobuff(Curschar->index, nn);
  2000.  
  2001.     while (Prenum > 0) {
  2002.         AppendToRedobuff("r");
  2003.         AppendToRedobuff(mkstr(nchar));
  2004.  
  2005.         AppendToUndobuff("r");
  2006.         AppendToUndobuff(mkstr(gchar(Curschar)));
  2007.  
  2008.         AppendToUndoUndobuff("r");
  2009.         AppendToUndoUndobuff(mkstr(nchar));
  2010.  
  2011.         pchar(Curschar, nchar);    /* Change current character. */
  2012.  
  2013.         if (Prenum > 1) {
  2014.         oneright();
  2015.         AppendToRedobuff("l");
  2016.         AppendToUndobuff("l");
  2017.         AppendToUndoUndobuff("l");
  2018.         }
  2019.         Prenum--;
  2020.     }
  2021.  
  2022.     CHANGED;
  2023.     updateline();
  2024.     break;
  2025.  
  2026.       case '~':        /* swap case */
  2027.     CLEAROP;
  2028.     if (lineempty(Curschar)) {
  2029.         beep();
  2030.         break;
  2031.     }
  2032.     ResetBuffers();
  2033.  
  2034.     n = RowNumber(Curschar);
  2035.     AppendPositionToUndobuff(Curschar->index, n);
  2036.     AppendPositionToUndoUndobuff(Curschar->index, n);
  2037.  
  2038.     Prenum = DEFAULT1(Prenum);
  2039.     if (Prenum > 0) {
  2040.         AppendNumberToRedobuff(Prenum);
  2041.         AppendNumberToUndobuff(Prenum);
  2042.         AppendNumberToUndoUndobuff(Prenum);
  2043.     }
  2044.     AppendToRedobuff("~");
  2045.     AppendToUndobuff("~");
  2046.     AppendToUndoUndobuff("~");
  2047.  
  2048.     while (Prenum > 0) {
  2049.         c = gchar(Curschar);
  2050.         if (isalpha(c)) {
  2051.         if (islower(c))
  2052.             pchar(Curschar, toupper(c));
  2053.         else
  2054.             pchar(Curschar, tolower(c));
  2055.         }
  2056.         if (!oneright())
  2057.         break;
  2058.         Prenum--;
  2059.     }
  2060.  
  2061.     CHANGED;
  2062.     updateline();
  2063.     break;
  2064.  
  2065.       case UNDO_SHIFTJ:
  2066.     CLEAROP;
  2067.     if (UndoInProgress) {
  2068.         if (dojoin(FALSE, FALSE)) {
  2069.         CHANGED;
  2070.         updateNextscreen();
  2071.         }
  2072.         break;
  2073.     }
  2074.     goto doSHIFTJcommand;
  2075.  
  2076.       case 'J':
  2077.     CLEAROP;
  2078. doSHIFTJcommand:
  2079.     if (nextline(Curschar) == NULL) {    /* on last line */
  2080.         beep();
  2081.         break;
  2082.     }
  2083.     ResetBuffers();
  2084.  
  2085.     temp_Curschar = *Curschar;
  2086.     nn = strlen(Curschar->linep->s);
  2087.     if (nn < 0)
  2088.         nn = 0;
  2089.     n = RowNumber(&temp_Curschar);
  2090.  
  2091.     AppendToRedobuff("J");
  2092.  
  2093.     AppendPositionToUndobuff(nn, n);
  2094.  
  2095.     AppendPositionToUndoUndobuff(0, n);
  2096.     AppendToUndoUndobuff("J");
  2097.  
  2098.     if (lineempty(nextline(Curschar))) {
  2099.         AppendToUndobuff("a\n");
  2100.         if (!dojoin(FALSE, TRUE)) {
  2101.         beep();
  2102.         break;
  2103.         }
  2104.     } else if (lineempty(Curschar)) {
  2105.         AppendToUndobuff("i\n");
  2106.         if (!dojoin(FALSE, TRUE)) {
  2107.         beep();
  2108.         break;
  2109.         }
  2110.     } else {
  2111.         AppendToUndobuff("dli\n");
  2112.         if (!dojoin(TRUE, TRUE)) {
  2113.         beep();
  2114.         break;
  2115.         }
  2116.     }
  2117.  
  2118.     AppendToUndobuff(ESC_STR);
  2119.     AppendPositionToUndobuff(nn, n);
  2120.  
  2121.     CHANGED;
  2122.     updateNextscreen();
  2123.     break;
  2124.  
  2125.       case K_CGRAVE:        /* shorthand command */
  2126.     CLEAROP;
  2127.     stuffReadbuff(":e #\n");
  2128.     break;
  2129.  
  2130.       case 'Z':        /* write, if changed, and exit */
  2131.     if (vgetc() != 'Z') {
  2132.         beep();
  2133.         break;
  2134.     }
  2135.     if (Changed) {
  2136.         if (Filename != NULL) {
  2137.         if (!writeit(Filename, (LPTR *) NULL, (LPTR *) NULL))
  2138.             return;
  2139.         } else {
  2140.         emsg("No output file");
  2141.         return;
  2142.         }
  2143.     }
  2144.     getout(0);
  2145.     break;
  2146.  
  2147.       case '.':
  2148.     CLEAROP;
  2149.     if (RedrawingDisabled) {
  2150.         RedrawingDisabled = FALSE;
  2151.         updateNextscreen();
  2152.     } else if (Redobuffptr != NULL) {
  2153.         stuffReadbuff(Redobuff);
  2154.         stuffReadbuff(".");
  2155.         RedrawingDisabled = TRUE;
  2156.     } else
  2157.         beep();
  2158.     break;
  2159.  
  2160.       case 'u':
  2161.       case K_UNDO:
  2162.     CLEAROP;
  2163.     if (UndoInProgress) {
  2164.         p = UndoUndobuff;
  2165.         UndoUndobuff = Undobuff;
  2166.         Undobuff = p;
  2167.         p = UndoUndobuffptr;
  2168.         UndoUndobuffptr = Undobuffptr;
  2169.         Undobuffptr = p;
  2170.  
  2171.         UndoInProgress = FALSE;
  2172.         RedrawingDisabled = FALSE;
  2173.         updateNextscreen();
  2174.     } else if (Undobuffptr != NULL) {
  2175.         stuffReadbuff(Undobuff);
  2176.         stuffReadbuff("u");
  2177.         UndoInProgress = TRUE;
  2178.         RedrawingDisabled = TRUE;
  2179.     } else {
  2180.         beep();
  2181.     }
  2182.     break;
  2183.  
  2184.       default:
  2185.     CLEAROP;
  2186.     beep();
  2187.     break;
  2188.     }
  2189.  
  2190.     /*
  2191.      * If an operation is pending, handle it... 
  2192.      */
  2193.     if (finish_op) {        /* we just finished an operator */
  2194.     if (operator == NOP)    /* ... but it was cancelled */
  2195.         return;
  2196.  
  2197.     switch (operator) {
  2198.  
  2199.       case LSHIFT:
  2200.       case RSHIFT:
  2201.         ResetBuffers();
  2202.  
  2203.         n = RowNumber(&startop);
  2204.         AppendPositionToUndobuff(startop.index, n);
  2205.         AppendPositionToUndoUndobuff(startop.index, n);
  2206.         if (Prenum != 0) {
  2207.         AppendNumberToRedobuff(Prenum);
  2208.         AppendNumberToUndobuff(Prenum);
  2209.         AppendNumberToUndoUndobuff(Prenum);
  2210.         }
  2211.         AppendToRedobuff((operator == LSHIFT) ? "<" : ">");
  2212.         AppendToUndobuff((operator == LSHIFT) ? ">" : "<");
  2213.         AppendToUndoUndobuff((operator == LSHIFT) ? "<" : ">");
  2214.         AppendToRedobuff(mkstr(c));
  2215.         if (c == '>')
  2216.         AppendToUndobuff("<");
  2217.         else if (c == '<')
  2218.         AppendToUndobuff(">");
  2219.         else
  2220.         AppendToUndobuff(mkstr(c));
  2221.         AppendToUndoUndobuff(mkstr(c));
  2222.  
  2223.         doshift(operator);
  2224.  
  2225.         CHANGED;
  2226.         break;
  2227.  
  2228.       case DELETE:
  2229.         ResetBuffers();
  2230.  
  2231.         n = RowNumber(&startop);
  2232.         AppendPositionToUndoUndobuff(startop.index, n);
  2233.  
  2234.         temp_Curschar = (lt(&startop, Curschar) ? startop : *Curschar);
  2235.         n = RowNumber(&temp_Curschar);
  2236.         if (Prenum != 0) {
  2237.         AppendNumberToRedobuff(Prenum);
  2238.         AppendNumberToUndoUndobuff(Prenum);
  2239.         }
  2240.         AppendToRedobuff("d");
  2241.         AppendToUndoUndobuff("d");
  2242.         AppendToRedobuff(mkstr(c));
  2243.         AppendToUndoUndobuff(mkstr(c));
  2244.         if (nchar != NUL) {
  2245.         AppendToRedobuff(mkstr(nchar));
  2246.         AppendToUndoUndobuff(mkstr(nchar));
  2247.         }
  2248.         AppendPositionToUndobuff(temp_Curschar.index, n);
  2249.  
  2250.         dodelete(TRUE, TRUE, TRUE);
  2251.  
  2252.         AppendPositionToUndobuff(temp_Curschar.index, n);
  2253.  
  2254.         CHANGED;
  2255.         break;
  2256.  
  2257.       case YANK:
  2258.         ResetBuffers();    /* no redo/undo/(undo of undo) on yank... */
  2259.         doyank();
  2260.         if (!ybcrossline)
  2261.         *Curschar = startop;
  2262.         else if (lt(&startop, Curschar))
  2263.         *Curschar = startop;
  2264.         break;
  2265.  
  2266.       case CHANGE:
  2267.         ResetBuffers();
  2268.  
  2269.         n = RowNumber(&startop);
  2270.         AppendPositionToUndoUndobuff(startop.index, n);
  2271.  
  2272.         temp_Curschar = (lt(&startop, Curschar) ? startop : *Curschar);
  2273.         n = RowNumber(&temp_Curschar);
  2274.         if (mtype == MLINE)
  2275.         AppendPositionToUndobuff(0, n);
  2276.         else
  2277.         AppendPositionToUndobuff(temp_Curschar.index, n);
  2278.  
  2279.         if (Prenum != 0) {
  2280.         AppendNumberToRedobuff(Prenum);
  2281.         AppendNumberToUndoUndobuff(Prenum);
  2282.         }
  2283.         AppendToRedobuff("c");
  2284.         AppendToUndoUndobuff("c");
  2285.         AppendToRedobuff(mkstr(c));
  2286.         AppendToUndoUndobuff(mkstr(c));
  2287.         if (nchar != NUL) {
  2288.         AppendToRedobuff(mkstr(nchar));
  2289.         AppendToUndoUndobuff(mkstr(nchar));
  2290.         }
  2291.         dochange();
  2292.  
  2293.         CHANGED;
  2294.  
  2295.         last_command = 'c';
  2296.         break;
  2297.  
  2298.       default:
  2299.         beep();
  2300.     }
  2301.     operator = NOP;
  2302.     }
  2303. }
  2304.  
  2305. /*
  2306.  * tabinout(shift_type, num) 
  2307.  *
  2308.  * If shift_type == RSHIFT, add a tab to the begining of the next num lines;
  2309.  * otherwise delete a tab from the beginning of the next num lines. 
  2310.  */
  2311. static void
  2312. tabinout(shift_type, num)
  2313.     int             shift_type;
  2314.     int             num;
  2315. {
  2316.     LPTR           *p;
  2317.  
  2318.     beginline(FALSE);
  2319.     while (num-- > 0) {
  2320.     beginline(FALSE);
  2321.     if (shift_type == RSHIFT)
  2322.         inschar(TAB);
  2323.     else {
  2324.         if (gchar(Curschar) == TAB)
  2325.         delchar(TRUE, FALSE);
  2326.     }
  2327.     if (num > 0) {
  2328.         if ((p = nextline(Curschar)) != NULL)
  2329.         *Curschar = *p;
  2330.         else
  2331.         break;
  2332.     }
  2333.     }
  2334. }
  2335.  
  2336. /*
  2337.  * doshift - handle a shift operation 
  2338.  */
  2339. static void
  2340. doshift(op)
  2341.     int             op;
  2342. {
  2343.     LPTR            top, bot;
  2344.     int             nlines;
  2345.  
  2346.     top = startop;
  2347.     bot = *Curschar;
  2348.  
  2349.     if (lt(&bot, &top))
  2350.     pswap(top, bot);
  2351.  
  2352.     nlines = cntllines(&top, &bot);
  2353.     *Curschar = top;
  2354.     tabinout(op, nlines);
  2355.  
  2356.     /*
  2357.      * The cursor position afterward is the prior of the two positions. 
  2358.      */
  2359.     *Curschar = top;
  2360.  
  2361.     /*
  2362.      * If we were on the last char of a line that got shifted left, then move
  2363.      * left one so we aren't beyond the end of the line 
  2364.      */
  2365.     if (gchar(Curschar) == NUL && Curschar->index > 0)
  2366.     Curschar->index--;
  2367.  
  2368.     if (op == RSHIFT)
  2369.     oneright();
  2370.     else
  2371.     oneleft();
  2372.  
  2373.     updateNextscreen();
  2374.  
  2375.     if (nlines > P(P_RP))
  2376.     smsg("%d lines %ced", nlines, (op == RSHIFT) ? '>' : '<');
  2377. }
  2378.  
  2379. /*
  2380.  * dodelete - handle a delete operation 
  2381.  */
  2382. static void
  2383. dodelete(redraw, setup_for_undo, try_to_yank)
  2384.     bool_t          redraw;
  2385.     bool_t          setup_for_undo;
  2386.     bool_t          try_to_yank;
  2387. {
  2388.     LPTR            top, bot;
  2389.     int             nlines;
  2390.     int             n;
  2391.  
  2392.     /*
  2393.      * Do a yank of whatever we're about to delete. If there's too much stuff
  2394.      * to fit in the yank buffer, then get a confirmation before doing the
  2395.      * delete. This is crude, but simple. And it avoids doing a delete of
  2396.      * something we can't put back if we want. 
  2397.      */
  2398.     if (try_to_yank) {
  2399.     if (!doyank()) {
  2400.         msg("yank buffer exceeded: press <y> to confirm");
  2401.         if (vgetc() != 'y') {
  2402.         msg("delete aborted");
  2403.         *Curschar = startop;
  2404.         return;
  2405.         }
  2406.     }
  2407.     }
  2408.     top = startop;
  2409.     bot = *Curschar;
  2410.  
  2411.     if (lt(&bot, &top))
  2412.     pswap(top, bot);
  2413.  
  2414.     *Curschar = top;
  2415.     nlines = cntllines(&top, &bot);
  2416.     cursupdate();
  2417.  
  2418.     if (mtype == MLINE) {
  2419.     if (operator == CHANGE) {
  2420.         last_command_char = 'a';
  2421.         delline(nlines - 1);
  2422.         Curschar->index = 0;
  2423.         while (delchar(TRUE, FALSE));
  2424.     } else {
  2425.         if (bot.linep->next == Fileend->linep)
  2426.         last_command_char = 'o';
  2427.         else
  2428.         last_command_char = 'O';
  2429.         if (setup_for_undo)
  2430.         AppendToUndobuff(mkstr(last_command_char));
  2431.         delline(nlines);
  2432.     }
  2433.     } else if (top.linep == bot.linep) {    /* del. within line */
  2434.     if (!mincl)
  2435.         dec(&bot);
  2436.  
  2437.     if (endofline(&bot))
  2438.         last_command_char = 'a';
  2439.     else
  2440.         last_command_char = 'i';
  2441.     if (setup_for_undo)
  2442.         AppendToUndobuff(mkstr(last_command_char));
  2443.     n = bot.index - top.index + 1;
  2444.     while (n--)
  2445.         if (!delchar(TRUE, FALSE))
  2446.         break;
  2447.     } else {            /* del. between lines */
  2448.     if (endofline(&top)) {
  2449.         if (nextline(&top)) {
  2450.         if (lineempty(nextline(&top)))
  2451.             last_command_char = 'a';
  2452.         else
  2453.             last_command_char = 'i';
  2454.         } else {
  2455.         last_command_char = 'a';
  2456.         }
  2457.     } else {
  2458.         last_command_char = 'i';
  2459.     }
  2460.     if (setup_for_undo)
  2461.         AppendToUndobuff(mkstr(last_command_char));
  2462.  
  2463.     n = Curschar->index;
  2464.     while (Curschar->index >= n)
  2465.         if (!delchar(TRUE, FALSE))
  2466.         break;
  2467.  
  2468.     top = *Curschar;
  2469.     *Curschar = *nextline(Curschar);
  2470.     delline(nlines - 2);
  2471.     Curschar->index = 0;
  2472.     n = bot.index;
  2473.     if (!mincl)
  2474.         n--;
  2475.  
  2476.     while (n-- >= 0)
  2477.         if (!delchar(TRUE, FALSE))
  2478.         break;
  2479.     *Curschar = top;
  2480.     dojoin(FALSE, FALSE);
  2481.     }
  2482.  
  2483.     if (mtype == MCHAR && nlines == 1 && redraw)
  2484.     updateline();
  2485.     else
  2486.     updateNextscreen();
  2487.  
  2488.     if (nlines > P(P_RP))
  2489.     smsg("%d fewer lines", nlines);
  2490.  
  2491.     if (setup_for_undo) {
  2492.     AppendToUndobuff(Yankbuff);
  2493.     AppendToUndobuff(ESC_STR);
  2494.     }
  2495. }
  2496.  
  2497. /*
  2498.  * dochange - handle a change operation 
  2499.  */
  2500. static void
  2501. dochange()
  2502. {
  2503.     bool_t          doappend;    /* true if we should do append, not insert */
  2504.  
  2505.     doappend = lt(Curschar, &startop);    /* needed for some compilers */
  2506.     doappend = endofline(doappend ? &startop : Curschar);
  2507.  
  2508.     dodelete(FALSE, FALSE, TRUE);
  2509.  
  2510.     if (doappend && !lineempty(Curschar))
  2511.     inc(Curschar);
  2512.  
  2513.     startinsert(FALSE);
  2514. }
  2515.  
  2516. static          bool_t
  2517. doyank()
  2518. {
  2519.     LPTR            top, bot;
  2520.     char           *ybend = &Yankbuff[YANKSIZE - 1];
  2521.     int             nlines;
  2522.  
  2523.     Yankbuffptr = Yankbuff;
  2524.  
  2525.     top = startop;
  2526.     bot = *Curschar;
  2527.  
  2528.     if (lt(&bot, &top))
  2529.     pswap(top, bot);
  2530.  
  2531.     nlines = cntllines(&top, &bot);
  2532.  
  2533.     ybtype = mtype;        /* set the yank buffer type */
  2534.     ybcrossline = FALSE;
  2535.     if (LINEOF(&top) != LINEOF(&bot))
  2536.     ybcrossline = TRUE;
  2537.  
  2538.     if (mtype == MLINE) {
  2539.     ybcrossline = TRUE;
  2540.     top.index = 0;
  2541.     bot.index = strlen(bot.linep->s);
  2542.     /*
  2543.      * The following statement checks for the special case of yanking a
  2544.      * blank line at the beginning of the file. If not handled right, we
  2545.      * yank an extra char (a newline). 
  2546.      */
  2547.     if (dec(&bot) == -1) {
  2548.         *Yankbuff = NUL;
  2549.         Yankbuffptr = NULL;
  2550.         return TRUE;
  2551.     }
  2552.     } else {
  2553.     if (!mincl)
  2554.         if (!equal(&top, &bot))
  2555.         dec(&bot);
  2556.     }
  2557.  
  2558.     for (; ltoreq(&top, &bot); inc(&top)) {
  2559.     *Yankbuffptr = (gchar(&top) != NUL) ? gchar(&top) : NL;
  2560.     Yankbuffptr++;
  2561.     if (Yankbuffptr >= ybend) {
  2562.         *Yankbuffptr = NUL;
  2563.         msg("yank too big for buffer");
  2564.         ybtype = MBAD;
  2565.         return FALSE;
  2566.     }
  2567.     }
  2568.  
  2569.     *Yankbuffptr = NUL;
  2570.  
  2571.     if (operator == YANK)
  2572.     if (nlines > P(P_RP))
  2573.         smsg("%d lines yanked", nlines);
  2574.  
  2575.     return TRUE;
  2576. }
  2577.  
  2578. static void
  2579. doput(dir)
  2580.     int             dir;
  2581. {
  2582.     bool_t          type;
  2583.  
  2584.     if (ybtype == MBAD) {
  2585.     beep();
  2586.     return;
  2587.     }
  2588.     type = (ybtype == MCHAR);
  2589.     if (dir == FORWARD)
  2590.     stuffReadbuff(type ? "a" : "o");
  2591.     else
  2592.     stuffReadbuff(type ? "i" : "O");
  2593.  
  2594.     stuffReadbuff(Yankbuff);
  2595.     stuffReadbuff(ESC_STR);
  2596. }
  2597.  
  2598. static void
  2599. startinsert(startln)
  2600.     int             startln;    /* if set, insert at start of line */
  2601. {
  2602.     *Insstart = *Curschar;
  2603.     if (startln) {
  2604.     Insstart->index = 0;
  2605.     }
  2606.     Insbuffptr = Insbuff;
  2607.     *Insbuffptr = NUL;
  2608.     State = INSERT;
  2609.     if (P(P_MO))
  2610.     msg("Insert Mode");
  2611. }
  2612.  
  2613. void
  2614. ResetBuffers()
  2615. {
  2616.     if (UndoInProgress)
  2617.     return;
  2618.  
  2619.     *Redobuff = NUL;
  2620.     Redobuffptr = NULL;
  2621.  
  2622.     *Undobuff = NUL;
  2623.     Undobuffptr = NULL;
  2624.  
  2625.     *UndoUndobuff = NUL;
  2626.     UndoUndobuffptr = NULL;
  2627. }
  2628.  
  2629. void
  2630. AppendToRedobuff(s)
  2631.     char           *s;
  2632. {
  2633.     if (UndoInProgress)
  2634.     return;
  2635.  
  2636.     if (Redobuffptr == NULL) {
  2637.     if ((strlen(s) + 1) < REDO_UNDO_SIZE) {
  2638.         strcpy(Redobuff, s);
  2639.         Redobuffptr = Redobuff;
  2640.     } else
  2641.         emsg("Couldn't AppendToRedobuff() - should never happen");
  2642.     return;
  2643.     }
  2644.     if ((strlen(Redobuff) + strlen(s) + 1) < REDO_UNDO_SIZE) {
  2645.     strcat(Redobuff, s);
  2646.     return;
  2647.     }
  2648.     emsg("Couldn't AppendToRedobuff() - should never happen");
  2649. }
  2650.  
  2651. void
  2652. AppendNumberToRedobuff(n)
  2653.     int             n;
  2654. {
  2655.     char            buf[32];
  2656.  
  2657.     if (UndoInProgress)
  2658.     return;
  2659.  
  2660.     sprintf(buf, "%d", n);
  2661.     AppendToRedobuff(buf);
  2662. }
  2663.  
  2664. void
  2665. AppendToUndobuff(s)
  2666.     char           *s;
  2667. {
  2668.     if (UndoInProgress)
  2669.     return;
  2670.  
  2671.     if (Undobuffptr == NULL) {
  2672.     if ((strlen(s) + 1) < REDO_UNDO_SIZE) {
  2673.         strcpy(Undobuff, s);
  2674.         Undobuffptr = Undobuff;
  2675.     } else
  2676.         emsg("Couldn't AppendToUndobuff() - should never happen");
  2677.     return;
  2678.     }
  2679.     if ((strlen(Undobuff) + strlen(s) + 1) < REDO_UNDO_SIZE) {
  2680.     strcat(Undobuff, s);
  2681.     return;
  2682.     }
  2683.     emsg("Couldn't AppendToUndobuff() - should never happen");
  2684. }
  2685.  
  2686. void
  2687. AppendNumberToUndobuff(n)
  2688.     int             n;
  2689. {
  2690.     char            buf[32];
  2691.  
  2692.     if (UndoInProgress)
  2693.     return;
  2694.  
  2695.     sprintf(buf, "%d", n);
  2696.     AppendToUndobuff(buf);
  2697. }
  2698.  
  2699. void
  2700. AppendPositionToUndobuff(column, row)
  2701.     int             column;
  2702.     int             row;
  2703. {
  2704.     if (UndoInProgress)
  2705.     return;
  2706.  
  2707.     AppendNumberToUndobuff(row);
  2708.     AppendToUndobuff("G");
  2709.     AppendNumberToUndobuff(column);
  2710.     if (column)
  2711.     AppendToUndobuff("l");
  2712. }
  2713.  
  2714. void
  2715. AppendToUndoUndobuff(s)
  2716.     char           *s;
  2717. {
  2718.     if (UndoInProgress)
  2719.     return;
  2720.  
  2721.     if (UndoUndobuffptr == NULL) {
  2722.     if ((strlen(s) + 1) < REDO_UNDO_SIZE) {
  2723.         strcpy(UndoUndobuff, s);
  2724.         UndoUndobuffptr = Undobuff;
  2725.     } else
  2726.         emsg("Couldn't AppendToUndoUndobuff() - should never happen");
  2727.     return;
  2728.     }
  2729.     if ((strlen(UndoUndobuff) + strlen(s) + 1) < REDO_UNDO_SIZE) {
  2730.     strcat(UndoUndobuff, s);
  2731.     return;
  2732.     }
  2733.     emsg("Couldn't AppendToUndoUndobuff() - should never happen");
  2734. }
  2735.  
  2736. void
  2737. AppendNumberToUndoUndobuff(n)
  2738.     int             n;
  2739. {
  2740.     char            buf[32];
  2741.  
  2742.     if (UndoInProgress)
  2743.     return;
  2744.  
  2745.     sprintf(buf, "%d", n);
  2746.     AppendToUndoUndobuff(buf);
  2747. }
  2748.  
  2749. void
  2750. AppendPositionToUndoUndobuff(column, row)
  2751.     int             column;
  2752.     int             row;
  2753. {
  2754.     if (UndoInProgress)
  2755.     return;
  2756.  
  2757.     AppendNumberToUndoUndobuff(row);
  2758.     AppendToUndoUndobuff("G");
  2759.     AppendNumberToUndoUndobuff(column);
  2760.     if (column)
  2761.     AppendToUndoUndobuff("l");
  2762. }
  2763.  
  2764. static          bool_t
  2765. dojoin(leading_space, strip_leading_spaces)
  2766.     bool_t          leading_space;
  2767.     bool_t          strip_leading_spaces;
  2768. {
  2769.     int             scol;    /* save cursor column */
  2770.     int             currsize;    /* size of the current line */
  2771.     int             nextsize;    /* size of the next line */
  2772.  
  2773.     if (nextline(Curschar) == NULL)    /* on last line */
  2774.     return FALSE;
  2775.  
  2776.     if (!canincrease(nextsize = strlen(Curschar->linep->next->s)))
  2777.     return FALSE;
  2778.  
  2779.     currsize = strlen(Curschar->linep->s);
  2780.  
  2781.     while (oneright());        /* to end of line */
  2782.  
  2783.     strcat(Curschar->linep->s, Curschar->linep->next->s);
  2784.  
  2785.     /*
  2786.      * Delete the following line. To do this we move the cursor there
  2787.      * briefly, and then move it back. Don't back up if the delete made us
  2788.      * the last line. 
  2789.      */
  2790.     Curschar->linep = Curschar->linep->next;
  2791.     scol = Curschar->index;
  2792.  
  2793.     if (nextline(Curschar) != NULL) {
  2794.     delline(1);
  2795.     Curschar->linep = Curschar->linep->prev;
  2796.     } else
  2797.     delline(1);
  2798.  
  2799.     Curschar->index = scol;
  2800.  
  2801.     if (currsize)
  2802.     oneright();        /* go to first char. of joined line */
  2803.  
  2804.     if (nextsize != 0 && strip_leading_spaces) {
  2805.     /*
  2806.      * Delete leading white space on the joined line and insert a single
  2807.      * space. 
  2808.      */
  2809.     while (gchar(Curschar) == ' ' || gchar(Curschar) == TAB) {
  2810.         delchar(TRUE, TRUE);
  2811.     }
  2812.     if (leading_space)
  2813.         inschar(' ');
  2814.     }
  2815.     return TRUE;
  2816. }
  2817.  
  2818. char           *
  2819. mkstr(c)
  2820.     char            c;
  2821. {
  2822.     static char     s[2];
  2823.  
  2824.     s[0] = c;
  2825.     s[1] = NUL;
  2826.  
  2827.     return s;
  2828. }
  2829. SHAR_EOF
  2830. cat << \SHAR_EOF > sendpacket.c
  2831. /*
  2832.  * Sendpacket.c 
  2833.  *
  2834.  * An invaluable addition to your Amiga.lib file. This code sends a packet the
  2835.  * given message port. This makes working around DOS lots easier. 
  2836.  *
  2837.  * Note, I didn't write this, those wonderful folks at CBM did. I do suggest
  2838.  * however that you may wish to add it to Amiga.Lib, to do so, compile it and
  2839.  * say 'oml lib:amiga.lib -r sendpacket.o' 
  2840.  */
  2841.  
  2842. #include <exec/types.h>
  2843. #include <exec/ports.h>
  2844. #include <exec/memory.h>
  2845. #include <libraries/dos.h>
  2846. #include <libraries/dosextens.h>
  2847.  
  2848. /*
  2849.  * Function - SendPacket written by Phil Lindsay, Carolyn Scheppner, and Andy
  2850.  * Finkel. This function will send a packet of the given type to the Message
  2851.  * Port supplied. 
  2852.  */
  2853.  
  2854. long
  2855. SendPacket(pid, action, args, nargs)
  2856.     struct MsgPort *pid;    /* process indentifier ... (handlers message
  2857.                  * port ) */
  2858.     long            action,    /* packet type ... (what you want handler to
  2859.                  * do )   */
  2860.                     args[],    /* a pointer to a argument list */
  2861.                     nargs;    /* number of arguments in list  */
  2862. {
  2863.     struct MsgPort *replyport;
  2864.     struct StandardPacket *packet;
  2865.  
  2866.     long            count, *pargs, res1;
  2867.  
  2868.     replyport = (struct MsgPort *) CreatePort(NULL, 0);
  2869.     if (!replyport)
  2870.     return (0);
  2871.  
  2872.     /* Allocate space for a packet, make it public and clear it */
  2873.     packet = (struct StandardPacket *)
  2874.     AllocMem((long) sizeof(struct StandardPacket), MEMF_PUBLIC | MEMF_CLEAR);
  2875.     if (!packet) {
  2876.     DeletePort(replyport);
  2877.     return (0);
  2878.     }
  2879.     packet->sp_Msg.mn_Node.ln_Name = (char *) &(packet->sp_Pkt);
  2880.     packet->sp_Pkt.dp_Link = &(packet->sp_Msg);
  2881.     packet->sp_Pkt.dp_Port = replyport;
  2882.     packet->sp_Pkt.dp_Type = action;
  2883.  
  2884.     /* copy the args into the packet */
  2885.     pargs = &(packet->sp_Pkt.dp_Arg1);    /* address of first argument */
  2886.     for (count = 0; count < nargs; count++)
  2887.     pargs[count] = args[count];
  2888.  
  2889.     PutMsg(pid, packet);    /* send packet */
  2890.  
  2891.     WaitPort(replyport);
  2892.     GetMsg(replyport);
  2893.  
  2894.     res1 = packet->sp_Pkt.dp_Res1;
  2895.  
  2896.     FreeMem(packet, (long) sizeof(struct StandardPacket));
  2897.     DeletePort(replyport);
  2898.  
  2899.     return (res1);
  2900. }
  2901. SHAR_EOF
  2902. #    End of shell archive
  2903. exit 0
  2904. -- 
  2905. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  2906. Have five nice days.
  2907.